package util

import (
	"bytes"
	"encoding/json"
	"io"
	"net/http"
	"strings"
	"yunj/pkg/global"
	"yunj/pkg/yunj/core/consts"

	"github.com/gin-gonic/gin"
)

// 当前请求是否来自移动设备
func IsMobile(ctx *gin.Context) bool {
	// 检查 User-Agent 头，判断请求是否来自移动端设备
	userAgent := ctx.GetHeader("User-Agent")
	mobileAgents := []string{
		"Mobile", "Android", "iPhone", "iPod", "BlackBerry", "IEMobile", "Opera Mini", "Windows Phone",
		// 可以添加更多特征，以提高检测的准确性
		"iPad", "Silk", // Amazon Silk
		"UCWEB", "UCBrowser", // UC Browser
		"Mobile Safari", "Chrome Mobile", "Firefox Mobile", // Mobile browsers
	}

	for _, agent := range mobileAgents {
		if strings.Contains(userAgent, agent) {
			return true
		}
	}
	return false
}

// 判断是否为内部系统请求
func IsInnerSystemRequest(ctx *gin.Context) bool {
	return strings.HasPrefix(ctx.Request.UserAgent(), consts.INNER_SYSTEM_USER_AGENT_PREFIX)
}

// 判断是否为异步请求
func IsAsync(ctx *gin.Context) bool {
	// 判断是否为ajax请求 或 请求是否期望返回JSON格式的数据 或 请求体是否JSON格式
	return ctx.GetHeader("X-Requested-With") == "XMLHttpRequest" || strings.Contains(ctx.GetHeader("Accept"), "application/json") || strings.Contains(ctx.GetHeader("Content-Type"), "application/json")
}

// 判断是否为post请求
func IsPost(ctx *gin.Context) bool {
	return ctx.Request.Method == http.MethodPost
}

// 判断是否为后台请求
func IsAdminRequest(ctx *gin.Context) bool {
	return strings.HasPrefix(ctx.Request.RequestURI, global.Config.GetAppAdminEntrance())
}

// 获取URL路径查询参数
func PathParams(ctx *gin.Context) map[string]string {
	params := make(map[string]string)
	for _, p := range ctx.Params {
		params[p.Key] = p.Value
	}
	return params
}

// 获取URL路径指定key查询参数
// 如：/article/:id
func PathParam(ctx *gin.Context, key string, def ...string) (value string) {
	if v := ctx.Param(key); v != "" {
		value = v
		return
	}
	if len(def) > 0 {
		value = def[0]
		return
	}
	return
}

// 获取URL路径指定key查询参数类型转换为uint64
func PathUint64Param(ctx *gin.Context, key string, def ...uint64) (value uint64) {
	if v := PathParam(ctx, key); v != "" {
		if val, err := ToUint64(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取URL路径指定key查询参数类型转换为uint8
func PathUint8Param(ctx *gin.Context, key string, def ...uint8) (value uint8) {
	if v := PathParam(ctx, key); v != "" {
		if val, err := ToUint8(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取URL路径指定key查询参数类型转换为int64
func PathInt64Param(ctx *gin.Context, key string, def ...int64) (value int64) {
	if v := PathParam(ctx, key); v != "" {
		if val, err := ToInt64(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取URL路径指定key查询参数类型转换为int
func PathIntParam(ctx *gin.Context, key string, def ...int) (value int) {
	if v := PathParam(ctx, key); v != "" {
		if val, err := ToInt(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取URL查询参数
func QueryParams(ctx *gin.Context) map[string]any {
	params := make(map[string]any)

	// 获取 URL 查询参数
	query := ctx.Request.URL.Query()
	for key, values := range query {
		if len(values) == 1 {
			params[key] = values[0]
		} else {
			params[key] = values
		}
	}
	return params
}

// 获取URL指定key查询参数
func QueryParam(ctx *gin.Context, key string, def ...string) (value string) {
	query := ctx.Request.URL.Query()
	valueRaw, exists := query[key]
	if !exists || len(valueRaw) <= 0 {
		if len(def) > 0 {
			value = def[0]
		}
		return
	}
	value = valueRaw[0]
	return
}

// 获取URL指定key查询参数类型转换为uint64
func QueryUint64Param(ctx *gin.Context, key string, def ...uint64) (value uint64) {
	if v := QueryParam(ctx, key); v != "" {
		if val, err := ToUint64(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取URL指定key查询参数类型转换为uint8
func QueryUint8Param(ctx *gin.Context, key string, def ...uint8) (value uint8) {
	if v := QueryParam(ctx, key); v != "" {
		if val, err := ToUint8(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取URL指定key查询参数类型转换为int64
func QueryInt64Param(ctx *gin.Context, key string, def ...int64) (value int64) {
	if v := QueryParam(ctx, key); v != "" {
		if val, err := ToInt64(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取URL指定key查询参数类型转换为int
func QueryIntParam(ctx *gin.Context, key string, def ...int) (value int) {
	if v := QueryParam(ctx, key); v != "" {
		if val, err := ToInt(v); err == nil {
			value = val
			return
		}
	}
	if len(def) > 0 {
		value = def[0]
	}
	return
}

// 获取所有的POST参数
func PostParams(ctx *gin.Context) (map[string]any, error) {
	params := make(map[string]any)

	// 检查请求的内容类型
	contentType := ctx.Request.Header.Get("Content-Type")

	// 尝试从表单数据中获取参数（仅当内容类型为 application/x-www-form-urlencoded 或 multipart/form-data 时）
	if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") || strings.HasPrefix(contentType, "multipart/form-data") {
		if err := ctx.Request.ParseForm(); err != nil {
			return nil, err
		}
		for key, values := range ctx.Request.PostForm {
			if len(values) == 1 {
				params[key] = values[0]
			} else {
				params[key] = values
			}
		}
	}

	// 尝试从 JSON 负载中获取参数
	if strings.HasPrefix(contentType, "application/json") {
		body, err := io.ReadAll(ctx.Request.Body)
		if err != nil {
			return nil, err
		}
		// fmt.Printf("json参数：%v\r\n", string(body))
		var jsonMap map[string]any
		if len(body) > 0 {
			if err := json.Unmarshal(body, &jsonMap); err != nil {
				return nil, err
			}
			for key, value := range jsonMap {
				params[key] = value
				// 将 JSON 值转换为字符串切片（这里只处理简单的值类型）
				// strVal, ok := value.(string)
				// if ok {
				// 	params[key] = []string{strVal}
				// } else {
				// 	// 对于非字符串值，你可能需要更复杂的处理逻辑
				// 	// 这里我们简单地忽略它们，但可以将它们转换为字符串或记录错误
				// 	// 例如：params[key] = []string{fmt.Sprintf("%v", value)}
				// }
			}
			// 注意：HTTP 请求体是一个 io.Reader，读取后会移动指针，导致后续无法再次读取。
			// 由于我们已经读取了请求体，所以如果后续的处理程序还需要访问请求体，
			// 你可能需要将请求体重新写入 ctx.Request.Body，或者使用其他方法来避免这个问题。
			// 一个简单的方法是使用 io.NopCloser(bytes.NewBuffer(body)) 来重新设置请求体。
			ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body))
		}
	}
	return params, nil
}

// 获取指定的POST参数
func PostParam(ctx *gin.Context, key string, def any) (value any, err error) {
	// 检查请求的内容类型
	contentType := ctx.Request.Header.Get("Content-Type")

	// 尝试从表单数据中获取参数（仅当内容类型为 application/x-www-form-urlencoded 或 multipart/form-data 时）
	if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") || strings.HasPrefix(contentType, "multipart/form-data") {
		if err = ctx.Request.ParseForm(); err != nil {
			return
		}
		for k, v := range ctx.Request.PostForm {
			if k != key {
				continue
			}
			if len(v) == 1 {
				value = v[0]
			} else {
				value = v
			}
			return
		}
	}

	// 尝试从 JSON 负载中获取参数
	if strings.HasPrefix(contentType, "application/json") {
		var body []byte
		body, err = io.ReadAll(ctx.Request.Body)
		if err != nil {
			return
		}
		var jsonMap map[string]any
		if err = json.Unmarshal(body, &jsonMap); err != nil {
			return
		}
		for k, v := range jsonMap {
			if k == key {
				value = v
				return
			}
		}
	}

	return def, nil
}

// 获取请求的所有参数
func GetAllParams(ctx *gin.Context) (map[string]any, error) {
	// get查询参数
	params := QueryParams(ctx)
	// post参数
	postParams, err := PostParams(ctx)
	if err != nil {
		return nil, err
	}
	// 合并参数
	for key, value := range postParams {
		params[key] = value
	}
	// path参数
	pathParams := PathParams(ctx)
	// 合并参数
	for key, value := range pathParams {
		params[key] = value
	}
	return params, nil
}
